using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.Collections.Generic;

namespace Nate.GUI.Canvas
{
    using Properties;

    public class Simple : Base
    {
        public Simple()
        {
            InitializeComponent();

            // Construct internal winform objects.
            _open_file_dialog                  = new OpenFileDialog();
            _open_file_dialog.Filter           = "Image files(*.png *.bmp *.jpg *.gif)|*.png; *.bmp; *.jpg; *.gif|All files|*.*";
            _open_file_dialog.InitialDirectory = ".\\";
            _open_file_dialog.RestoreDirectory = true;

            // Build internal data.
            _default_cursor         = Cursor;
            Blackboard.GuiBB.Bmp    = Resources.Grid_A;            
            ClickState              = ClickState.None;
            Scalar                  = _default_scalar;

            // Build the object that manages the toolbar buttons.
            _buttons                   = new Simple.Buttons();
            _buttons.OnOpenImage      += new Simple.Buttons.Event(_ButtonClicked_OpenImage);
            _buttons.OnZoomIn         += new Simple.Buttons.Event(_ButtonClicked_ZoomIn);
            _buttons.OnZoomOut        += new Simple.Buttons.Event(_ButtonClicked_ZoomOut);
            _buttons.OnSetPathFrom    += new Simple.Buttons.Event(_ButtonClicked_SetPathFrom);
            _buttons.OnSetPathTo      += new Simple.Buttons.Event(_ButtonClicked_SetPathTo);
            _buttons.OnAllowDiagonals += new Simple.Buttons.Event(_CheckStateChanged_Diagonals);
            _buttons.OnAllowVariable  += new Simple.Buttons.Event(_CheckStateChanged_Variable);

            // Register Windows event handlers
            MouseClick  += new MouseEventHandler(_MouseClick);
        }

        #region CanvasControlAbstract Overrides
        protected override ToolStripItem[]  GenerateToolStripItems()
        {
            List<ToolStripItem> items = new List<ToolStripItem>();
            _buttons.Populate(items);
            return items.ToArray();
        }
        protected override void             HandlePaint(object sender, PaintEventArgs e)
        {
            Graphics graphics = e.Graphics;
            graphics.DrawImage(Bitmap, RenderBitmapRectF);

            RectangleF[] path = RenderPath;
            if (null != path)
            {
                Brush path_brush = RenderPathBrush;
                foreach (RectangleF rect in path)
                {
                    graphics.FillRectangle(path_brush, rect);
                }
            }
            if (PointF.Empty != RenderPathStart)
            {
                Bitmap bmp = RenderPathStartBitmap;

                PointF p = new PointF(RenderPathStart.X, RenderPathStart.Y);
                p.X -= (float)bmp.Width / 2.0f;
                p.Y -= (float)bmp.Height / 2.0f;

                graphics.DrawImage(bmp, p);
            }
            if (PointF.Empty != RenderPathEnd)
            {
                Bitmap bmp = RenderPathEndBitmap;

                PointF p = new PointF(RenderPathEnd.X, RenderPathEnd.Y);
                p.X -= (float)bmp.Width / 2.0f;
                p.Y -= (float)bmp.Height / 2.0f;

                graphics.DrawImage(bmp, p);
            }
        }
        protected override void             Autosize()
        {
            Scalar = (float)ParentControl.Height / (float)Blackboard.GuiBB.Bmp.Height;
        }
        public    override void             ZoomIn()
        { 
            Scalar += _default_scalar;
            RefreshCanvas();
        }
        public    override void             ZoomOut()
        {
            Scalar -= _default_scalar;
            RefreshCanvas();
        }
        #endregion

        private ToolStripMenuItem toolStripMenuItem1;
        private ToolStripMenuItem setTargetToolStripMenuItem;



        #region Internal Render Accessors
        private Bitmap       Bitmap
        {
            get
            {
                return Blackboard.GuiBB.Bmp;
            }
        }
        private RectangleF   RenderBitmapRectF
        {
            get
            {
                return new RectangleF(0, 0, (float)Blackboard.GuiBB.Bmp.Width * Scalar, (float)Blackboard.GuiBB.Bmp.Height * Scalar);
            }
        }
        private RectangleF[] RenderPath
        {
            get
            {
                List<Point>      points_unscaled = Blackboard.PathingBB.Path;
                List<RectangleF> rects = new List<RectangleF>();

                if (null != points_unscaled)
                {
                    foreach (Point p in points_unscaled)
                    {
                        RectangleF rect = new RectangleF((float)p.X * Scalar, (float)p.Y * Scalar, Scalar, Scalar);
                        rects.Add(rect);
                    }
                }

                return rects.ToArray();
            }
        }
        private PointF       RenderPathStart
        {
            get
            {
                return new PointF((float)Blackboard.GuiBB.Start.X * Scalar, (float)Blackboard.GuiBB.Start.Y * Scalar);
            }
        }
        private PointF       RenderPathEnd
        {
            get
            {
                return new PointF((float)Blackboard.GuiBB.Dest.X * Scalar,  (float)Blackboard.GuiBB.Dest.Y * Scalar);
            }
        }
        private Bitmap       RenderPathStartBitmap
        {
            get
            {
                return Resources.lorry;
            }
        }
        private Bitmap       RenderPathEndBitmap
        {
            get
            {
                return Resources.star;
            }
        }
        private Brush        RenderPathBrush
        {
            get
            {
                switch(Blackboard.PathingBB.Status)
                {
                    case Shared.Status.Failure:
                        return Brushes.Red;
                    case Nate.Shared.Status.InProcess:
                        return Brushes.Yellow;
                    case Nate.Shared.Status.Success:
                        return Brushes.Green;
                    case Nate.Shared.Status.None:
                        return Brushes.Red;
                }
                return Brushes.Red;
            }
        }
        #endregion

        #region Private Data
        public float            Scalar
        {
            get
            {
                return _scalar;
            }
            set
            {
                _scalar = value;
                if (_scalar < 0.1f)
                {
                    _scalar = 0.1f;
                }

                Width   = (int)((float)Blackboard.GuiBB.Bmp.Width * _scalar);
                Height  = (int)((float)Blackboard.GuiBB.Bmp.Height * _scalar);
                Refresh();
            }
        }
        public ClickState       ClickState
        {
            get
            {
                return _click_state;
            }
            set
            {
                _click_state = value;

                // Exit out early for the default cursor.
                if (ClickState.None == value)
                {
                    Cursor = _default_cursor;
                    return;
                }

                // Set the icon to match the click state we're going into
                Bitmap bmp = null;
                switch (value)
                {
                    case ClickState.PathDest:
                        bmp = new Bitmap(Resources.star);
                        break;
                    case ClickState.PathStart:
                        bmp = new Bitmap(Resources.lorry);
                        break;
                    default:
                        bmp = new Bitmap(Resources.exclamation);
                        break;
                }

                // Use handy dandy create cursor method to make the cursor.
                Cursor = NUtils.Cursor.CreateCursor(bmp.GetHicon(), bmp.Width / 2, bmp.Height / 2);
            }
        }

        private ClickState      _click_state;
        private float           _scalar;
        private Buttons         _buttons;
        private OpenFileDialog  _open_file_dialog;
        private Cursor          _default_cursor;
        private ContextMenuStrip _context_menu_strip;
        private System.ComponentModel.IContainer components;

        private const float     _default_scalar = 1.0f;
        #endregion

        #region Event Handlers
        private void _MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }

            // Convert mouse location to the pathfinder's space.
            Point pnt = new Point((int)((float)e.Location.X / Scalar), (int)((float)e.Location.Y / Scalar));

            switch (ClickState)
            {
                case ClickState.PathDest:
                    Blackboard.GuiBB.Dest  = pnt;                    
                    Refresh();
                    break;
                case ClickState.PathStart:
                    Blackboard.GuiBB.Start = pnt;
                    Refresh();
                    break;
            }
        }

        void _ButtonClicked_OpenImage(ToolStripButton button, EventArgs e)
        {
            NUtils.Console.Spam(@"Look for new image");
            _open_file_dialog.ShowDialog();

            if (_open_file_dialog.FileName == null ||
                _open_file_dialog.FileName.Length < 1)
            {
                return;
            }

            Blackboard.GuiBB.Bmp = new Bitmap(_open_file_dialog.FileName);
            Autosize();
            Refresh();
        }

        void _ButtonClicked_ZoomIn(ToolStripButton button, EventArgs e)
        {
            ZoomIn();
        }

        void _ButtonClicked_ZoomOut(ToolStripButton button, EventArgs e)
        {
            ZoomOut();
        }

        void _ButtonClicked_SetPathFrom(ToolStripButton button, EventArgs e)
        {
            ClickState = ClickState.PathStart;
        }

        void _ButtonClicked_SetPathTo(ToolStripButton button, EventArgs e)
        {
            ClickState = ClickState.PathDest;
        }

        void _CheckStateChanged_Diagonals(ToolStripButton button, EventArgs e)
        {
            if (button.CheckState == CheckState.Checked)
            {
                Blackboard.GuiBB.AllowDiagonals = true;
                button.Text = "Uncheck again to disallow diagonal edges";
                return;
            }

            Blackboard.GuiBB.AllowDiagonals = false;
            button.Text = "Check to allow diagonal edges";
        }

        void _CheckStateChanged_Variable(ToolStripButton button, EventArgs e)
        {
            if (button.CheckState == CheckState.Checked)
            {
                Blackboard.GuiBB.AllowVariable = true;
                button.Text = "Uncheck to disallow variable weighting on nodes (all non-black pixels are equal cost)";
                return;
            }

            Blackboard.GuiBB.AllowVariable = false;
            button.Text = "Check to allow variable weighting on nodes (darker pixels become more expensive)";
        }


        #endregion

        private class Buttons
        {
            static Size _button_size    = new System.Drawing.Size(31, 20);
            static Size _separator_size = new System.Drawing.Size(31, 6);

            ToolStripSeparator  _separator1;
            ToolStripSeparator  _separator2;
            ToolStripSeparator  _separator3;
            ToolStripSeparator  _separator4;
            ToolStripButton     _open_image;
            ToolStripButton     _zoom_in;
            ToolStripButton     _zoom_out;
            ToolStripButton     _set_path_from;
            ToolStripButton     _set_path_to;
            ToolStripButton     _allow_diagonals;
            ToolStripButton     _allow_variable;

            event Event         _open_image_clicked;
            event Event         _zoom_in_clicked;
            event Event         _zoom_out_clicked;
            event Event         _set_path_from_clicked;
            event Event         _set_path_to_clicked;
            event Event         _allow_diagonals_changed;
            event Event         _allow_variable_changed;

            void _OpenImage_Clicked  (object sender, EventArgs e) { _open_image_clicked(_open_image, e); }
            void _ZoomIn_Clicked     (object sender, EventArgs e) { _zoom_in_clicked(_zoom_in, e); }
            void _ZoomOut_Clicked    (object sender, EventArgs e) { _zoom_out_clicked(_zoom_out, e); }
            void _SetPathFrom_Clicked(object sender, EventArgs e) { _set_path_from_clicked(_set_path_from, e); }
            void _SetPathTo_Clicked  (object sender, EventArgs e) { _set_path_to_clicked(_set_path_to, e); }

            void _AllowDiagonals_CheckStateChanged(object sender, EventArgs e) { _allow_diagonals_changed(_allow_diagonals, e); }
            void _AllowVariable_CheckStateChanged(object sender, EventArgs e) { _allow_variable_changed(_allow_variable, e); }

            public delegate void Event(ToolStripButton button, EventArgs e);

            public event Event OnOpenImage
            {
                add
                {
                    _open_image_clicked += value;
                }
                remove
                {
                    _open_image_clicked -= value;
                }
            }
            public event Event OnZoomIn
            {
                add
                {
                    _zoom_in_clicked += value;
                }
                remove
                {
                    _zoom_in_clicked -= value;
                }
            }
            public event Event OnZoomOut
            {
                add
                {
                    _zoom_out_clicked += value;
                }
                remove
                {
                    _zoom_out_clicked -= value;
                }
            }
            public event Event OnSetPathFrom
            {
                add
                {
                    _set_path_from_clicked += value;
                }
                remove
                {
                    _set_path_from_clicked -= value;
                }
            }
            public event Event OnSetPathTo
            {
                add
                {
                    _set_path_to_clicked += value;
                }
                remove
                {
                    _set_path_to_clicked -= value;
                }
            }
            public event Event OnAllowDiagonals
            {
                add
                {
                    _allow_diagonals_changed += value;
                }
                remove
                {
                    _allow_diagonals_changed -= value;
                }
            }
            public event Event OnAllowVariable
            {
                add
                {
                    _allow_variable_changed += value;
                }
                remove
                {
                    _allow_variable_changed -= value;
                }
            }

            private void _Construct(ref ToolStripSeparator separator, string name)
            {
                separator = new ToolStripSeparator();
                separator.Name = name;
                separator.Size = _separator_size;
            }

            private void _Construct(ref ToolStripButton button, string text, Image image, EventHandler onClick, string name)
            {
                button = new ToolStripButton(text, image, onClick, name);
                button.DisplayStyle = ToolStripItemDisplayStyle.Image;
                button.ImageTransparentColor = System.Drawing.Color.Magenta;
                button.Size = _button_size;
            }

            private void _ConstructCheckable(ref ToolStripButton button, string text, Image image, EventHandler onCheckStateChanged, string name)
            {
                button = new ToolStripButton(text, image, null, name);
                button.DisplayStyle = ToolStripItemDisplayStyle.Image;
                button.ImageTransparentColor = System.Drawing.Color.Magenta;
                button.Size = _button_size;
                button.CheckOnClick = true;
                button.CheckStateChanged += onCheckStateChanged;               
            }

            public Buttons()
            {
                _Construct(ref _separator1, "separator1");
                _Construct(ref _separator2, "separator2");
                _Construct(ref _separator3, "separator3");
                _Construct(ref _separator4, "separator4");

                _Construct(ref _open_image,     "Open Image",     Resources.folder_picture,     _OpenImage_Clicked,   "_open_image");
                _Construct(ref _zoom_in,        "Zoom In",        Resources.magnifier_zoom_in,  _ZoomIn_Clicked,      "_zoom_in");
                _Construct(ref _zoom_out,       "Zoom Out",       Resources.magnifier_zoom_out, _ZoomOut_Clicked,     "_zoom_out");
                _Construct(ref _set_path_from,  "Set Path Start", Resources.lorry,              _SetPathFrom_Clicked, "_set_path_from");
                _Construct(ref _set_path_to,    "Set Path End",   Resources.star,               _SetPathTo_Clicked,   "_set_path_to");

                _ConstructCheckable(ref _allow_diagonals, "Check to allow diagonal edges", Resources.arrow_out, _AllowDiagonals_CheckStateChanged, "_allow_diagonals");
                _ConstructCheckable(ref _allow_variable, "Check to allow variable weighting on nodes (darker pixels become more expensive)", Resources.layers, _AllowVariable_CheckStateChanged, "_allow_variable");
            }

            public void Populate(List<ToolStripItem> items)
            {
                items.Add(_open_image);
                items.Add(_separator1);
                items.Add(_zoom_in);
                items.Add(_zoom_out);
                items.Add(_separator2);
                items.Add(_set_path_from);
                items.Add(_set_path_to);
                items.Add(_separator3);
                items.Add(_allow_diagonals);
                items.Add(_allow_variable);
                items.Add(_separator4);
            }
            
        }

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this._context_menu_strip = new System.Windows.Forms.ContextMenuStrip(this.components);
            this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
            this.setTargetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this._context_menu_strip.SuspendLayout();
            this.SuspendLayout();
            // 
            // _context_menu_strip
            // 
            this._context_menu_strip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.toolStripMenuItem1,
            this.setTargetToolStripMenuItem});
            this._context_menu_strip.Name = "_context_menu_strip";
            this._context_menu_strip.Size = new System.Drawing.Size(154, 48);
            this._context_menu_strip.Text = "Set Target";
            // 
            // toolStripMenuItem1
            // 
            this.toolStripMenuItem1.Image = global::Nate.GUI.Properties.Resources.lorry;
            this.toolStripMenuItem1.Name = "toolStripMenuItem1";
            this.toolStripMenuItem1.Size = new System.Drawing.Size(153, 22);
            this.toolStripMenuItem1.Text = "Set Path Start";
            this.toolStripMenuItem1.Click += new System.EventHandler(this._SetPathStart);
            // 
            // setTargetToolStripMenuItem
            // 
            this.setTargetToolStripMenuItem.Image = global::Nate.GUI.Properties.Resources.star;
            this.setTargetToolStripMenuItem.Name = "setTargetToolStripMenuItem";
            this.setTargetToolStripMenuItem.Size = new System.Drawing.Size(153, 22);
            this.setTargetToolStripMenuItem.Text = "Set Target";
            this.setTargetToolStripMenuItem.Click += new System.EventHandler(this._SetPathDest);
            // 
            // Simple
            // 
            this.ContextMenuStrip = this._context_menu_strip;
            this.Name = "Simple";
            this._context_menu_strip.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        private void _SetPathStart(object sender, EventArgs e)
        {
            // Convert mouse location to the pathfinder's space.
            Point location = _context_menu_strip.PointToScreen(new Point(0, 0));
            location = PointToClient(location);

            Point pnt = new Point((int)((float)location.X / Scalar), (int)((float)location.Y / Scalar));

            Blackboard.GuiBB.Start = pnt;
            Refresh();
        }

        private void _SetPathDest(object sender, EventArgs e)
        {
            // Convert mouse location to the pathfinder's space.
            Point location = _context_menu_strip.PointToScreen(new Point(0, 0));
            location = PointToClient(location);
            
            Point pnt = new Point((int)((float)location.X / Scalar), (int)((float)location.Y / Scalar));

            Blackboard.GuiBB.Dest = pnt;
            Refresh();
        }
    }
}